<?php

/**
 * This is the model class for table "{{menu}}".
 *
 * The followings are the available columns in table '{{menu}}':
 * @property integer $id
 * @property string $title
 * @property string $alias
 * @property integer $status
 * @property integer $parent_id
 * @property integer $display_order
 * @property string $link
 * @property integer $extension_id
 * @property string $param
 * @property string $access
 * @property integer $target_window
 * @property string $language
 * @property integer $default_page
 * @property integer $menu_type_id
 * @property string $meta_desc
 * @property string $meta_keyword
 * @property string $robots
 * @property string $page_title
 * @property string $css_style
 * @property string $create_date
 * @property string $created_by
 * @property string $update_date
 * @property string $updated_by
 *
 * The followings are the available model relations:
 * @property Extension $extension
 * @property MenuType $menu
 */
class Menu extends CActiveRecord {

    public $icon = NULL;
    public $childs = array();
    public $level = 0;
    public $isUp = NULL;
    public $isDown = NULL;
    public $categoryId;
    public $article;
    public $external_link;
    public $old_parent_id;
    public $album_id;

    const SCENARIO_SEARCH = 'search';
    const SCENARIO_CREATE = 'create';
    const SCENARIO_UPDATE = 'update';
    const SCENARIO_ORDER = 'order';
    const ACTION_DOWN = 'down';
    const ACTION_UP = 'up';
    const ALIAS_MAX_LENGTH = 50;

    /**
     * Returns the static model of the specified AR class.
     * @param string $className active record class name.
     * @return Menu the static model class
     */
    public static function model($className = __CLASS__) {
	return parent::model($className);
    }

    /**
     * @return string the associated database table name
     */
    public function tableName() {
	return '{{menu}}';
    }

    /**
     * @return array validation rules for model attributes.
     */
    public function rules() {
	// NOTE: you should only define rules for those attributes that
	// will receive user inputs.
	return array(
	    array('title, link, extension_id, menu_type_id', 'required'),
	    array('parent_id, display_order, extension_id, target_window, default_page, menu_type_id', 'numerical', 'integerOnly' => true),
	    array('status', 'checkTriggerParentStatus', 'on' => Menu::SCENARIO_CREATE . ',' . Menu::SCENARIO_UPDATE, 'message' => t('MSG_PARENT_STATUS_IS_UNPUBLISHED', 'messages')),
	    array('title, alias, link, param, meta_keyword, page_title', 'length', 'max' => 255),
	    array('access', 'length', 'max' => 50),
	    array('language', 'length', 'max' => 25),
	    array('meta_desc', 'length', 'max' => 500),
	    array('robots', 'length', 'max' => 30),
	    array('css_style', 'length', 'max' => 100),
	    array('alias', 'length', 'max' => Menu::ALIAS_MAX_LENGTH),
	    // The following rule is used by search().
	    // Please remove those attributes that should not be searched.
	    array('id, title, alias, status, parent_id, display_order, link, extension_id, param, access, target_window, language, default_page, menu_type_id, meta_desc, meta_keyword, robots, page_title, css_style, create_date, created_by, update_date, updated_by', 'safe', 'on' => 'search'),
	    array('old_parent_id', 'safe'),
	    array('alias', 'duplicateItem', 'on' => self::SCENARIO_CREATE . ',' . self::SCENARIO_UPDATE),
	    array('param', 'validateParam')
		//array('external_link', 'url'),
	);
    }

    public function validateParam($attribute, $params) {
	switch ($this->extension_id) {
	    case LGConstantExtensionType::CATEGORY_BLOG:
		if (!isset($this->param) || empty($this->param)) {
		    $this->addError('categoryId', 'This field is required.');
		} else {
		      try {
			$obj = json_decode($this->param);
		    } catch (Exception $ex) {
			$this->addError('categoryId', 'This field is required.');
		    }

		    if (!isset($obj->id)) {
			$this->addError('categoryId', 'This field is required.');
		    }

		    $category = Category::model()->findByPk($obj->id);

		    if ($category == null) {
			$this->addError('categoryId', 'This field is required.');
		    }
		}
		
		
		break;
	    case LGConstantExtensionType::EXTERNAL_LINK:
		if (!isset($this->link) || empty($this->link)) {
		    $this->addError('external_link', 'This field is required.');
		}
		break;
	    case LGConstantExtensionType::GALLERY_ITEM:
		if (!isset($this->param) || empty($this->param)) {
		    $this->addError('album_id', 'This field is required.');
		} else {
		      try {
			$obj = json_decode($this->param);
		    } catch (Exception $ex) {
			$this->addError('album_id', 'This field is required.');
		    }

		    if (!isset($obj->id)) {
			$this->addError('album_id', 'This field is required.');
		    }

		    $category = Album::model()->findByPk($obj->id);

		    if ($category == null) {
			$this->addError('album_id', 'This field is required.');
		    }
		}
		break;
	    case LGConstantExtensionType::SINGLE_ARTICLE:
		if (!isset($this->param) || empty($this->param)) {
		    $this->addError('article', 'This field is required.');
		} else {
		    try {
			$obj = json_decode($this->param);
		    } catch (Exception $ex) {
			$this->addError('article', 'This field is required.');
		    }

		    if (!isset($obj->id)) {
			$this->addError('article', 'This field is required.');
		    }

		    $article = Article::model()->findByPk($obj->id);

		    if ($article == null) {
			$this->addError('article', 'This field is required.');
		    }
		}



		break;
	    default :
	}
    }

    /*
     * Check rule: 
     * 	    If a category is changed to published status, and any its super nodes have an unpublished status. This action will be save and show messsage 'Cannot change the published status when the parent category is of a unpublished status.'
     */

    public function checkTriggerParentStatus($attribute, $params) {

	if ($this->status == LGConstant::PUBLISH_STATUS) {
	    if (Menu::AreAllSuperMenuUnpusblishedStatus($this)) {
		$message = isset($params['message']) ?
			$params['message'] : t('MSG_PARENT_STATUS_IS_UNPUBLISHED', 'messamge');
		$this->addError($attribute, $message);
	    }
	}
    }

    public static function AreAllSuperMenuUnpusblishedStatus($menuModel) {
	$parentMenu = $menuModel->getParentMenu();

	if ($parentMenu == null) {
	    return false;
	}

	if ($parentMenu->status == LGConstant::UNPUBLISH_STATUS) {
	    return true;
	}

	return Menu::AreAllSuperMenuUnpusblishedStatus($parentMenu);
    }

    /**
     * 
     * @return 
     */
    public function getParentMenu() {

	if (!isset($this->parent_id) || empty($this->parent_id)) {
	    return null;
	}
	return $this->findByPk($this->parent_id);
    }

    public function duplicateItem($attribute) {
	$alias = trim($this->alias);

	if (!$alias) {
	    $alias = stringSafe($this->title);
	} else {
	    $alias = stringSafe($alias);
	}

	$criteria = new CDbCriteria();
	$criteria->addCondition("id != :id AND alias = :alias AND parent_id = :parent_id");
	$criteria->params = array(':id' => $this->id == null ? '' : $this->id, ':alias' => $alias, ':parent_id' => $this->parent_id);
	$result = $this->findAll($criteria);


	if (count($result) > 0) {
	    //Show alias is be duplicated to display view
	    $this->alias = $alias;

	    $this->addError($attribute, t('MSG_ERROR_DUPLICATED_ALIAS', 'messages'));
	}
    }

    /**
     * @return array relational rules.
     */
    public function relations() {
	// NOTE: you may need to adjust the relation name and the related
	// class name for the relations automatically generated below.
	return array(
	    'menu' => array(self::BELONGS_TO, 'MenuType', 'menu_type_id'),
	    'extension' => array(self::BELONGS_TO, 'Extension', 'extension_id'),
	);
    }

    /**
     * @return array customized attribute labels (name=>label)
     */
    public function attributeLabels() {
	return array(
	    'id' => 'ID',
	    'title' => t('LBL_TITLE', 'menu'),
	    'alias' => t('LBL_ALIAS', 'menu'),
	    'status' => t('LBL_STATUS', 'menu'),
	    'parent_id' => t('LBL_PARENT', 'menu'),
	    'display_order' => t('LBL_DISPLAY_ORDER', 'menu'),
	    'link' => t('LBL_LINK', 'menu'),
	    'extension_id' => t('LBL_TYPE', 'menu'),
	    'param' => 'Param',
	    'access' => t('LBL_ACCESS', 'menu'),
	    'target_window' => t('LBL_TARGET_WINDOW', 'menu'),
	    'language' => t('LBL_LANGUAGE', 'menu'),
	    'default_page' => 'Default Page',
	    'menu_type_id' => t('LBL_MENU', 'menu'),
	    'meta_desc' => t('LBL_META_DESC', 'menu'),
	    'meta_keyword' => t('LBL_META_KEYWORD', 'menu'),
	    'robots' => t('LBL_ROBOTS', 'menu'),
	    'page_title' => t('LBL_PAGE_TITLE', 'menu'),
	    'css_style' => t('LBL_CSS_STYLE', 'menu'),
	    'create_date' => 'Create Date',
	    'created_by' => 'Created By',
	    'update_date' => 'Update Date',
	    'updated_date' => 'Updated By',
	    'category_id' => t('LBL_SELECT_CATEGORY', 'menu'),
	    'article' => t('LBL_SELECT_ARTICLE', 'menu'),
	    'external_link' => t('LBL_EXTERNAL_LINK', 'menu'),
	    'album_id' => t('LBL_GALLERY', 'menu'),
	);
    }

    /**
     * Retrieves a list of models based on the current search/filter conditions.
     * @return CActiveDataProvider the data provider that can return the models based on the search/filter conditions.
     */
    public function search() {
	// Warning: Please modify the following code to remove attributes that
	// should not be searched.

	$criteria = new CDbCriteria;

	$criteria->compare('id', $this->id);
	$criteria->compare('title', $this->title, true);
	$criteria->compare('alias', $this->alias, true);
	$criteria->compare('status', $this->status);
	$criteria->compare('parent_id', $this->parent_id);
	$criteria->compare('display_order', $this->display_order);
	$criteria->compare('link', $this->link, true);
	$criteria->compare('extension_id', $this->extension_id);
	$criteria->compare('param', $this->param, true);
	$criteria->compare('access', $this->access, true);
	$criteria->compare('target_window', $this->target_window);
	$criteria->compare('language', $this->language, true);
	$criteria->compare('default_page', $this->default_page);
	$criteria->compare('menu_type_id', $this->menu_type_id);
	$criteria->compare('meta_desc', $this->meta_desc, true);
	$criteria->compare('meta_keyword', $this->meta_keyword, true);
	$criteria->compare('robots', $this->robots, true);
	$criteria->compare('page_title', $this->page_title, true);
	$criteria->compare('css_style', $this->css_style, true);
	$criteria->compare('create_date', $this->create_date, true);
	$criteria->compare('created_by', $this->created_by, true);
	$criteria->compare('update_date', $this->update_date, true);
	$criteria->compare('updated_by', $this->updated_by, true);

	return new CActiveDataProvider($this, array(
	    'criteria' => $criteria,
	));
    }

    public function publish() {
	if ($this->status == LGConstant::PUBLISH_STATUS) {
	    return true;
	}
	$this->status = LGConstant::PUBLISH_STATUS;
	return $this->saveAttributes(array('status'));
    }

    public function unpublish() {
	if ($this->status == LGConstant::UNPUBLISH_STATUS) {
	    return true;
	}
	$this->status = LGConstant::UNPUBLISH_STATUS;
	return $this->saveAttributes(array('status'));
    }

    public function getExtensionIds() {
	$listData = Extension::model()->findAll();
	return CHtml::listData($listData, 'id', 'name');
    }

    public function getStatuses() {
	return CHtml::listData(LGHelpers::getStatusMenu(), 'id', 'name');
    }

    public function getAccesses() {
	return CHtml::listData(LGHelpers::getAccess(), 'id', 'name');
    }

    public function getTargetWindows() {
	return CHtml::listData(LGHelpers::getTargetWindow(), 'id', 'name');
    }

    public function getRobots() {
	return CHtml::listData(LGHelpers::getRobots(), 'id', 'name');
    }

    public function getMenus() {
	$listData = MenuType::model()->findAll();
	return CHtml::listData($listData, 'id', 'name');
    }

    public function getDefaultPages() {
	return CHtml::listData(LGHelpers::getDefaultPages(), 'id', 'name');
    }

    public function beforeSave() {
	if (parent::beforeSave()) {
	    $current_date = date(LGConstant::DATE_FORMAT_FOR_DATABASE);
	    $logedInUser = User::model()->findByPk(Yii::app()->user->id);

	    //$this->alias = !isset ($this->alias) || $this->alias == "" ? stringURLSafe($this->title) : stringURLSafe($this->alias);
	    $alias = $this->alias;
	    if (isset($this->alias) && strlen($this->alias) > 0) {
		$alias = trim($alias);
		$this->alias = stringURLSafe($alias);
	    } else {
		$this->alias = substr(stringURLSafe($this->title), 0, Menu::ALIAS_MAX_LENGTH);

		//If alias is empty, join link and alias
		//Because Javascript from client will remove alias of link attribute, when alias textbox is empty.
		//We need to join link and alias if alias is empty
		//Contact us is no alias
		if ($this->extension_id == LGConstantExtensionType::SINGLE_ARTICLE ||
			$this->extension_id == LGConstantExtensionType::CATEGORY_BLOG ||
			$this->extension_id == LGConstantExtensionType::GALLERY_ITEM) {
		    $this->link .= '-' . $this->alias;
		}
	    }

	    if ($this->create_date == NULL) {
		$this->create_date = $current_date;
	    }

	    if ($this->created_by == NULL) {
		$this->created_by = $logedInUser->username;
	    }

	    if ($this->display_order == 0) {
		$max_category = $this->getMaxDisplayOrder($this->parent_id);
		$this->display_order = $max_category['display_order'] + 1;
	    }

	    $this->update_date = $current_date;
	    $this->updated_by = $logedInUser->username;

	    return true;
	} else {
	    return false;
	}
    }

    function afterSave() {
	if (!$this->isNewRecord) {
	    $menu = $this->searchByParentID($this->parent_id);
	    $count = 1;

	    if ($this->parent_id != $this->old_parent_id) {

		foreach ($menu as $data) {
		    if ($data['id'] != $this->id) {
			$child_menu = $this->findByPk($data['id']);
			$child_menu->display_order = $count;
			$child_menu->saveAttributes(array('display_order'));
			$count++;
		    }
		}

		$this->display_order = $count;
		$this->saveAttributes(array('display_order'));
	    }

	    $menu_parent = $this->find('parent_id = :parent_id', array(':parent_id' => $this->parent_id));
	    $parent = $this->findByPk($menu_parent->parent_id);

	    if ($parent != NULL) {
		$list_menu_parent = $this->searchByParentID($parent->parent_id);
		$count_parent = 1;

		foreach ($list_menu_parent as $value) {
		    $child_menu_parent = $this->findByPk($value['id']);
		    $child_menu_parent->display_order = $count_parent;
		    $child_menu_parent->saveAttributes(array('display_order'));
		    $count_parent++;
		}
	    }

	    if ($this->parent_id != $this->old_parent_id) {

		if (!$this->isNewRecord) {
		    $old_menu = $this->searchByParentID($this->old_parent_id);
		    $count_old_parent = 1;

		    foreach ($old_menu as $data) {
			$child_menu = $this->findByPk($data['id']);
			$child_menu->display_order = $count_old_parent;
			$child_menu->saveAttributes(array('display_order'));
			$count_old_parent++;
		    }
		}
	    }
	}
	parent::afterSave();
    }

    public function getMaxDisplayOrder($parent_id) {
	$criteria = new CDbCriteria();
	$criteria->select = 'max(display_order) as display_order';
	$criteria->addCondition("parent_id = :parent_id");
	$criteria->params = array(':parent_id' => $parent_id);
	return $this->find($criteria);
    }

    public function getMinDisplayOrder($parent_id) {
	$criteria = new CDbCriteria();
	$criteria->select = 'min(display_order) as display_order';
	$criteria->addCondition("parent_id = :parent_id");
	$criteria->params = array(':parent_id' => $parent_id);
	return $this->find($criteria);
    }

    public function getParentID($id, $menuTypeId = NULL) {
	$listData = $this->getDataForParentDropDownList(NULL, $id, $menuTypeId);
	return CHtml::listData($listData, 'id', 'title');
    }

    function getDataForParentDropDownList($arr = NULL, $currentId = 0, $menuTypeID = NULL) {
	if (!$arr)
	    $arr = array();
	$tempArray = array();
	$finalArray = array();

	if ($menuTypeID != NULL) {

	    $this->menu_type_id = $menuTypeID;
	}

	$arr = LGHelpers::buildTreeArray($this->getAllParentAndChildMenu());
	LGHelpers::exposeTreeArray($arr, $tempArray, '— ');
	if ($currentId != 0) {
	    $menu = $this->getAllMenuNodesHaveRootSpecifiedID($currentId);
	    if (count($menu) > 0) {
		foreach ($menu as $model) {
		    foreach ($tempArray as $index => $value) {
			if ($model['id'] == $value['id'] || $value['id'] == $currentId) {
			    unset($tempArray[$index]);
			}
		    }
		}
	    } else {
		foreach ($tempArray as $index => $value) {
		    if ($value['id'] == $currentId) {
			unset($tempArray[$index]);
		    }
		}
	    }
	}
	foreach ($tempArray as $model) {
	    if ($model['status'] == LGConstant::UNPUBLISH_STATUS) {
		$finalArray[] = array(
		    'id' => $model['id'],
		    'title' => $model['indent'] . '[' . $model['title'] . ']');
	    } else {
		$finalArray[] = array(
		    'id' => $model['id'],
		    'title' => $model['indent'] . $model['title']);
	    }

//            $finalArray[] = array("id" => $model['id'],
//                "title" => $model['indent'] . $model['title']);
	}

	return $finalArray;
    }

    public function getAllMenuNodesHaveRootSpecifiedID($id, $arr = NULL) {
	if (!$arr)
	    $arr = array();

	$menu = $this->searchByParentID($id);
	foreach ($menu as $data) {
	    $arr[] = array('id' => $data['id'], 'title' => $data['title']);
	    $arr = $this->getAllMenuNodesHaveRootSpecifiedID($data['id'], $arr);
	}
	return $arr;
    }

    /**
     * Get all node have root node which has id is $id
     * @param type $id
     * @param type $extension
     * @param type $arr
     * @return array<Menu>
     */
    public function getAllNodesHaveRootSpecifiedID($id, $arr = NULL) {
	if (!$arr)
	    $arr = array();

	$menu = $this->searchByParentID($id);
	foreach ($menu as $data) {
	    $arr[] = $data;
	    $arr = $this->getAllNodesHaveRootSpecifiedID($data['id'], $arr);
	}
	return $arr;
    }

    public function searchByParentID($parent_id) {
	$criteria = new CDbCriteria();

	$criteria->addCondition("parent_id = :parent_id");
	$criteria->params = array(':parent_id' => $parent_id);
	//$criteria->order = 'display_order ASC';
	return $this->findAll($criteria);
    }

//    public function getListMenu() {
//	$paginate = new CPagination();
//	$paginate->pageSize = LGHelpers::getPageSize($this->count());
//
//	$model = new Menu();
//	$model->menu_type_id = '2';
//	$myArr = $this->getDataForIndex();
//
//	$dataProvider = new CArrayDataProvider($myArr);
//	$dataProvider->pagination = $paginate;
//	return $dataProvider;
//    }
//    public function getDataForIndex($arr = NULL) {
//
//	if (!$arr)
//	    $arr = array();
//	$finalArray = array();
//	$arr = LGHelpers::buildTreeArray($this->getAllParentAndChildMenu());
//	LGHelpers::exposeTreeArray($arr, $finalArray, '|— ');
//	$count = 0;
//
//	foreach ($finalArray as $data) {
//	    $max_order = $this->getMaxDisplayOrder($data['parent_id']);
//	    $min_order = $this->getMinDisplayOrder($data['parent_id']);
//
//	    if ((int) $max_order['display_order'] == (int) $min_order['display_order']) {
//		$finalArray[$count]['order_column'] =
//			'<input class="icon up disable" type="button">'
//			. '<input class="icon down disable" type="button">';
//	    } else if ((int) $data['display_order'] == (int) $min_order['display_order']) {
//		$finalArray[$count]['order_column'] =
//			'<input class="icon down" onclick="LGCMS.ajaxCallback(\'' . Yii::app()->baseUrl . '/menu/order?id=' . $data['id'] . '&order=' . $data['display_order'] . '&action=down\')" name="yt2" type="button">'
//			. '<input class="icon up disable" type="button">';
//	    } else if ((int) $data['display_order'] == (int) $max_order['display_order']) {
//		$finalArray[$count]['order_column'] =
//			'<input class="icon down disable" type="button">'
//			. '<input class="icon up" onclick="js:LGCMS.ajaxCallback(\'' . Yii::app()->baseUrl . '/menu/order?id=' . $data['id'] . '&order=' . $data['display_order'] . '&action=up\')" name="yt2" type="button">';
//	    } else {
//		$finalArray[$count]['order_column'] =
//			'<input class="icon down" onclick="js:LGCMS.ajaxCallback(\'' . Yii::app()->baseUrl . '/menu/order?id=' . $data['id'] . '&order=' . $data['display_order'] . '&action=down\')" name="yt2" type="button">'
//			. '<input class="icon up" onclick="js:LGCMS.ajaxCallback(\'' . Yii::app()->baseUrl . '/menu/order?id=' . $data['id'] . '&order=' . $data['display_order'] . '&action=up\')" name="yt2" type="button">';
//	    }
//	    $count++;
//	}
//	return $finalArray;
//    }

    public function getAllParentAndChildMenu() {
	$arr = array();

	$criteria = new CDbCriteria();
	if ($this->menu_type_id != null && $this->menu_type_id != '') {
	    $criteria->compare('menu_type_id', $this->menu_type_id);
	}
	if ($this->status != null && $this->status != '') {
	    $criteria->compare('status', $this->status);
	}
	if ($this->access != null && $this->access != '') {
	    $criteria->compare('access', $this->access);
	}
	if ($this->default_page != null && $this->default_page != '') {
	    $criteria->compare('default_page', $this->default_page);
	}
	if ($this->language != null && $this->language != '') {
	    $criteria->compare('language', $this->language);
	}
	if ($this->title != null && $this->title != '') {
	    $criteria->addSearchCondition('title', trim($this->title), TRUE);
	}

	if ($this->menu_type_id != null && $this->menu_type_id != '') {
	    $criteria->compare('menu_type_id', $this->menu_type_id);
	}

	//$menuData = $this->findAll($criteria, array('order' => 'display_order ASC'));
	$menuData = $this->findAll($criteria);
	foreach ($menuData as $model) {
	    $arr[$model->id] = array("id" => $model['id'],
		"parent_id" => $model['parent_id'],
		"order" => $model['display_order'],
		"title" => $model['title'],
		"alias" => $model['alias'],
		'status' => $model['status'],
		'display_order' => $model['display_order'],
		'access' => $model['access'],
		'extension_name' => $model['extension']->name,
		'default_page' => $model['default_page'],
		'language' => $model['language'],
		'id' => $model['id'],
		'order_column' => '',
	    );
	}
	return $arr;
    }

    public function getMenuByTypeId($menuTypeId) {
	//get menu language from setting
	setLanguage(isset($_GET['lang']) ? $_GET['lang'] : null);

	if (isset($_GET['lang'])) {
	    $language = $_GET['lang'];
	} else {
	    $settingLanguage = Settings::model()->findAll();
	    $language = $settingLanguage[0]->language;
	}
	//Compare menu language
	$criteria = new CDbCriteria();
	$criteria->alias = 'menu';
	$criteria->join = 'LEFT JOIN {{menu_type}} ON {{menu_type}}.id=menu.menu_type_id';
	$criteria->addCondition("menu.status = 1 and {{menu_type}}.status = 1 and menu_type_id like :type_id and 
            (language like :language OR language like '*')");
	$criteria->params = array('type_id' => $menuTypeId, 'language' => $language);
	$menus = $this->findAll($criteria);

	//get menu language if menu is *
//        $criteria = new CDbCriteria();
//        $criteria->alias = 'menu';
//        $criteria->join = 'LEFT JOIN {{menu_type}} ON {{menu_type}}.id=menu.menu_type_id';
//        $criteria->addCondition("menu.status = 1 and {{menu_type}}.status = 1 and menu_type_id like :type_id and 
//            language like :language");
//        $criteria->params = array('type_id' => $menuTypeId, 'language' => "*");
//        $menusAll = $this->findAll($criteria);
//
//        $menus = array_merge($menus, $menusAll);

	$modelArr = array();
	/* @var $model Menu */
	foreach ($menus as $model) {
	    $url = (is_null($model->link) || $model->link == '' || $model->link == 'javascript:void(0);') ? 'javascript:void(0);' : $model->link;

	    $htmlOptions = array();
	    if (strpos($_SERVER['REQUEST_URI'], $url) !== FALSE) {
		$htmlOptions['active'] = true;
	    }

	    if ($model->extension_id != LGConstantExtensionType::EXTERNAL_LINK) {
		$url = url($url);
	    }

	    $targetValue = 'default';
	    $scriptOpenWindowTemplate = "window.open('%s','','fullscreen=no,directories=0,titlebar=yes,toolbar=no,location=0,status=yes,menubar=0,scrollbars=yes,resizable=yes')";
	    $scriptOpenWindow = '';
	    $htmlOptions = array_merge($htmlOptions, array('id' => $model->id, 'parent_id' => $model->parent_id, 'order' => $model->display_order, 'label' => $model->title, 'url' => $url));

	    if (isset($model->css_style) && !empty($model->css_style)) {
		$htmlOptions['itemOptions'] = array('class' => $model->css_style);
	    }

	    switch ($model->target_window) {
		case LGConstantTargetWindowType::PARENT:
		    break;
		case LGConstantTargetWindowType::NEW_WINDOW_WITH_NAVIGATION:
		    $targetValue = '_blank';
		    $htmlOptions['linkOptions'] = array('target' => $targetValue);
		    break;

		case LGConstantTargetWindowType::NEW_WINDOW_WITH_NO_NAVIGATION:
		    $scriptOpenWindow = sprintf($scriptOpenWindowTemplate, $url);
		    //Set url to "#"
		    $htmlOptions['url'] = '#';
		    $htmlOptions['linkOptions'] = array('onclick' => $scriptOpenWindow);
		    break;
	    }
	    $modelArr[$model->id] = $htmlOptions;
	}

	return LGHelpers::buildTreeArray($modelArr);
    }

    /*
     * Get All sub items and delete them before delete the current item
     */

    public function beforeDelete() {
	if (parent::beforeDelete()) {
	    $list_child_menu = $this->getAllNodesHaveRootSpecifiedID($this->id);

	    foreach ($list_child_menu as $data) {
		$menu = new Menu();
		$menu->deleteByPk($data['id']);
	    }
	    return true;
	} else {
	    return false;
	}
    }

    /**
     * After Delete, reduce display_order of items which are in behind the deleting item 
     */
    public function afterDelete() {
	parent::afterDelete();

	$list_menu = $this->getMenuForUpdate($this->parent_id, $this->display_order);
	foreach ($list_menu as $value) {
	    $menu = new Menu();
	    $menu_entity = $menu->model()->findByPk($value['id']);
	    $menu_entity->display_order = (int) $value['display_order'] - 1;
	    $menu_entity->update();
	}
    }

    public function getMenuForUpdate($parent_id, $display_order) {
	$criteria = new CDbCriteria();
	$criteria->addCondition("parent_id = :parent_id and display_order >= :display_order");
	$criteria->params = array(':parent_id' => $parent_id, ':display_order' => $display_order);
	$criteria->order = 'display_order ASC';
	return $this->findAll($criteria);
    }

    public function searchByDisplayOrder($order, $parent_id) {
	$criteria = new CDbCriteria();
	$criteria->addCondition("display_order = :display_order && parent_id = :parent_id");
	$criteria->params = array(':display_order' => $order, ':parent_id' => $parent_id);
	$result = $this->findAll($criteria);
	return $result[0];
    }

    /*
     * When a category changes status, all its subs will be change to its status.
     * @return return true if updated successfully. Else return false. Add error to model if occur when validation.
     */

    public function changeStatus($newStatus) {

	if ($this->status != $newStatus) {
	    $this->status = $newStatus;
	    if (!$this->validate(array('status'))) {
		return false;
	    }
	    $transaction = $this->dbConnection->beginTransaction();

	    $isSuccess = true;
	    if ($this->saveAttributes(array('status'))) {
		if (!$this->changeAllSubsStatus()) {
		    $isSuccess = false;
		}
	    } else {
		$isSuccess = false;
	    }

	    if ($isSuccess) {
		$transaction->commit();
	    } else {
		$transaction->rollback();
	    }

	    return $isSuccess;
	} else {
	    return false;
	}
    }

    /*
     * When a category changes status, all its subs will be change to its status.
     * return true if updated successfully. Else return false
     */

    public function changeAllSubsStatus() {

	$menu = Menu::model()->getAllNodesHaveRootSpecifiedID($this->id);
	$isSuccess = true;

	//Create a sql command to update new status
	$sqlQuery = "UPDATE " . $this->tableName() . " SET status = $this->status WHERE 1 = 0 ";

	$temp = " OR id = ";
	foreach ($menu as $item) {
	    $id = $item->id;
	    $condition = $temp . $item->id;
	    $sqlQuery.= $condition;
	}

	$connection = Yii::app()->db;
	$command = $connection->createCommand($sqlQuery);
	try {
	    $rowCount = $command->execute(); // execute the non-query SQL
	} catch (Exception $exc) {
	    $isSuccess = false;
	}

	return $isSuccess;
    }

    /**
     * Data Tree For GridView
     * @param type $pageSize
     * @return \CActiveDataProvider
     */
    public static function getProductTypeTreeDataProvider($model = NULL, $pageSize = 0) {

	$criteria = new CDbCriteria();
	if ($model == NULL) {
	    $model = self::model();

	    $criteria->compare('status', 0);
//$criteria->order = 'parent_id ASC';
	} else {


	    $criteria->compare('status', $model->status);

	    $criteria->compare('parent_id', $model->parent_id);
	    $criteria->compare('access', $model->access);
	    $criteria->compare('default_page', $model->default_page);
	    $criteria->compare('language', $model->language);
	    $criteria->compare('menu_type_id', $model->menu_type_id);
	    $criteria->addSearchCondition('title', trim($model->title));
	}
	$criteria->order = 'parent_id ASC, display_order ASC';
	$pageSize = $pageSize == 0 ? $model->count($criteria) : $pageSize;


	$productTypes = new CActiveDataProvider($model, array(
	    'criteria' => $criteria,
	    'pagination' => array(
		'pageSize' => $model->count($criteria)
	    )
	));


	$level1Nodes = self::organizeTree($productTypes->data);
	$resultArr = self::convertTreeToArray($level1Nodes);

	if ($resultArr == NULL) {
	    $resultArr = array();
	}

	$pagination = new CPagination;
	$pagination->itemCount = $model->count($criteria);
	$pagination->pageSize = $pageSize;

	$page = isset($_GET['page']) ? $_GET['page'] : 1;
	if ($page > $pagination->itemCount / $pageSize + 1) {
	    $page = intval($pagination->itemCount / $pageSize) + 1;
	} else if ($page == $pagination->itemCount / $pageSize + 1) {
	     $page = intval($pagination->itemCount / $pageSize);
	}

	$resultArr = array_slice($resultArr, ($page - 1) * $pageSize, $pageSize);
	$productTypes->setData($resultArr);
	$productTypes->setPagination($pagination);

	return $productTypes;
    }

    /*
     * @param Menu $model
     */

    public static function getLevel($model) {
	if ($model == null) {
	    throw new InvalidArgumentException();
	}

	return self::getParentNodeLevel($model->parent_id);
    }

    /**
     * Using recursive to get parent node level
     * @param type $parentID
     * @return int
     */
    public static function getParentNodeLevel($parentID) {
	$parent = self::getParentProductType($parentID);

	if ($parent == NULL) {
	    return 0;
	}

	return self::getParentNodeLevel($parent->parent_id) + 1;
    }

    protected static function getParentProductType($parentID) {
	if ($parentID == NULL) {
	    return NULL;
	}

	return self::model()->findByPk($parentID);
    }

    /**
     * Data Tree For DropDownList. Must be remove it and it's child, if not creae
     * cycle relationship
     * @return type
     */
    public static function getProductTypeTreeArray($productTypeID = NULL) {
	$model = self::model();
	$criteria = new CDbCriteria();
	$criteria->compare('status', 0);
//$criteria->order = 'parent_id ASC';
	$criteria->order = 'parent_id ASC, display_order ASC';
	$pageSize = $model->count();

	$productTypes = new CActiveDataProvider($model, array(
	    'criteria' => $criteria,
	    'pagination' => false,
	));

	$level1Nodes = self::organizeTree($productTypes->data);

	if ($productTypeID != NULL) {
	    self::removeANode($level1Nodes, $productTypeID);
	}

	$resultArr = self::convertTreeToArray($level1Nodes);


	return $resultArr;
    }

    /**
     * 
     * @param type $nodes
     * @param type $nodeID
     * @return boolean false when have not found yet. esle return true
     */
    private static function removeANode(&$nodes, $nodeID /* productTypeID */) {

	if ($nodes == NULL)
	    return false;
	$lenght = count($nodes);
	for ($i = 0; $i < $lenght; $i++) {
	    $node = $nodes[$i];
	    if ($node != NULL) {
		if ($node->id == $nodeID) {
//             $nodes = array_diff($nodes, array($node));
		    array_splice($nodes, $i, 1);
//             if (isset($node->childs)) {
//                $node->childs = array();
//             }

		    return true;
		}


		if ($node->childs != NULL && count($node->childs) > 0) {
		    $isFound = self::removeANode($node->childs, $nodeID);

		    if ($isFound) {
			return true;
		    }
		}
	    }
	}

	return false;
    }

    /**      2
     *      /
     *     1
     *      \
     *       3---3.1
     * 
     *        5---5.1
     *       /
     *      4
     *       \
     *        6
     * @param type $productTypes
     * @return array
     */
    public static function organizeTree($productTypes) {
	$arr = array();
	$rootID = NULL;
	$level = -1;
	$productType = null;

//Contains root nodes
	$resultArr = array();

//Find items have parent_id not existed in array
//They are root nodes
	foreach ($productTypes as $m) {
	    $isExsit = false;
	    if ($m->parent_id == NULL) {
		array_push($arr, $m);
		array_push($resultArr, $m);
		continue;
	    }

	    foreach ($productTypes as $n) {
		if ($n->id == $m->parent_id) {
		    $isExsit = true;
		    break;
		}
	    }

	    if (!$isExsit) {
		array_push($arr, $m);
		array_push($resultArr, $m);
	    }
	}

//Find child of item in $arr, and add childs for them
	do {
	    $productType = array_pop($arr);

	    if ($productType != NULL) {
		$rootID = $productType->id;
		$level = $productType->level;
	    }

	    foreach ($productTypes as $value) {
		if ($value->parent_id == $rootID) {
		    $value->level = $level + 1;
		    $arr[] = $value;

		    array_push($productType->childs, $value);
		}
	    }
	} while ($productType != NULL);

	return $resultArr;
    }

    public static function convertTreeToArray($level1Nodes) {
//      $temp = new SOProductType;
//      $temp->childs = $level1Nodes;
//      $temp->sortChilds();
	if (count($level1Nodes) > 0) {

	    $clonedArr = (array) clone(object) $level1Nodes;
	    $sortLevel1Nodes = array();
	    while (count($clonedArr) > 0) {
		$arrKey = array_keys($clonedArr);
		$selectingNode = $clonedArr[$arrKey[0]];

		array_splice($clonedArr, 0, 1);
		$group = array($selectingNode);

		foreach ($clonedArr as $node) {
		    if ($node->parent_id == $selectingNode->parent_id) {
			array_push($group, $node);
		    }
		}

		$temp = self::model();
		$temp->childs = $group;
		$temp->sortChilds();

		$sortLevel1Nodes = array_merge($sortLevel1Nodes, $temp->childs);
		foreach ($group as $node) {
		    if (($key = array_search($node, $clonedArr)) !== false) {
			unset($clonedArr[$key]);
		    }
		}
		//$clonedArr = array_udiff($clonedArr, $group, 'compare_objects');
	    }

//	    $level1Nodes[0]->isUp = NULL;
//	    end($level1Nodes)->isDown = NULL;

	    $arr = $sortLevel1Nodes;

	    for ($i = 0; $i < count($arr); $i++) {
		$node = $arr[$i];

		if ($node == NULL || $node->childs == NULL || count($node->childs) == 0) {
		    continue;
		    ;
		}

		$node->sortChilds();

		array_splice($arr, $i + 1, 0, $node->childs);
	    }

	    return $arr;
	}
    }

    public function sortChilds() {
	if ($this->childs != NULL && count($this->childs) > 0) {
	    usort($this->childs, "cmp");
	    $length = count($this->childs);

	    for ($i = 0; $i < $length; $i++) {
		if ($i - 1 < 0) {
		    $this->childs[$i]->isUp = NULL;
		} else {
		    $this->childs[$i]->isUp = $this->childs[$i - 1]->id;
		}

		if ($i + 1 >= $length) {
		    $this->childs[$i]->isDown = NULL;
		} else {
		    $this->childs[$i]->isDown = $this->childs[$i + 1]->id;
		}
	    }
	}
    }

}
